package com.hsmpay.yl8583.service;

import com.hsmpay.common.pojo.qian4.Qian4SendLog;
import com.hsmpay.utils.*;
import com.hsmpay.utils.NumberUtil;
import com.hsmpay.utils.system.ConConfig;
import com.hsmpay.yl8583.utils.TestDes;
import com.iso8583.Iso8583Composer;
import com.iso8583.Iso8583Parser;
import com.iso8583.util.ByteUtils;
import com.iso8583.util.J8583Util;
import com.iso8583.util.PosUtil;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by zhy on 15/11/10.
 */
public class HanXinToBoss {
    static WriteFile wf = new WriteFile("ds_HanXin");
    public static String debug = ConConfig.getAttribute("HANXIN-DAISHOU-DEBUG-STATUS");
    //翰鑫通道参数信息
    String ipAddr = "";
    String port = "";
    String localIp = "";//放到配置文件中

    String shopCode = "";//商户号
    String posNo = "";//终端号
    String tpdu = "6000060000";
    String header = "601003000000";
    String batch = "000001";
    String mainKey = "";
    String muKey = "";
    String pinKey = "";
    String macKey = "";
    String trkKey = "";
    String sensKey = "";//敏感信息秘钥
    String orgId = "";//机构号

    /**
     *
     * @param merchantId
     * @param terminalId
     * @param batch
     * @param mainKey 加密的终端主密钥
     * @param pinKey
     * @param macKey
     * @param trkKey
     */
    public HanXinToBoss(String merchantId, String terminalId, String batch, String mainKey, String pinKey, String macKey, String trkKey, String sensKey, Map<String, String> hanXinConfig){
        /*
        *  配置翰鑫通道参数
        *
        * */
        if (null!= hanXinConfig){
            this.ipAddr = hanXinConfig.get("ip");
            this.port = hanXinConfig.get("port");
            this.orgId = hanXinConfig.get("orgId");
            this.localIp = hanXinConfig.get("localIp");
        }

        if (StringUtils.isNotBlank(mainKey)){
            this.mainKey = mainKey;
        }
        if (StringUtils.isNotEmpty(batch)){
            this.batch = batch;
        }else{
            this.batch = "000001";
        }
        this.shopCode = merchantId;
        this.posNo = terminalId;
        this.pinKey = pinKey;
        this.macKey = macKey;
        this.trkKey = trkKey;
        this.sensKey = sensKey;
        wf.log("tpdu:" + this.tpdu, "调试");
        wf.log("ShopCode(商户号):" + this.shopCode, "调试");
        wf.log("PosNo(终端号):" + this.posNo, "调试");
        wf.log("batch(批次号):" + this.batch, "调试");
        wf.log("MuKey:" + this.muKey, "调试");//数据库保存是 主秘钥
        wf.log("mainKey:" + this.mainKey, "调试");
        wf.log("PinKey:" + this.pinKey, "调试");
        wf.log("MacKey:" + this.macKey, "调试");
        wf.log("trkKey:" + this.trkKey, "调试");
    }

    /**
     * 银行卡余额查询
     *
     * @param trk2 二磁道数据
     * @param trk3 二磁道数据
     * @param pin  卡交易密码
     * @param accountNumber 主账号
     * @param serialNumber 受卡方系统跟踪号
     * @return 订单信息
     * @throws Exception
     */
    public String Query(String trk2, String trk3, String pin, String accountNumber, String serialNumber, String bit23, String bit55, String bit14) throws Exception {
        //String des_pin = Des3.encryptPin(accountNumber, pin, "5CF180B0BAB52DAACDA295241C0D39E4");
        Date date = new Date();
        String temp53 = TimeUtils.getDateTime(date, "ddHHmmss") + NumberUtil.generateRandom8Number(8);
        String des_pin = TestDes.MakeDesPin(accountNumber, pin, pinKey, mainKey);
        String QueryMsg = "";
        String TYPE_ID = "0200";
        String mustFields = "";
        StringBuffer optionalFields = new StringBuffer("");
        HashMap<String,String> body = new HashMap<String,String>();
        wf.log("-------------------请求包域值信息-------------------", "调试");
        body.put("TPDU", this.tpdu);
        body.put("HEAD", this.header);
        //第2 61 62域敏感信息域
//        String temp2 = TestDes.encryptSpecial(temp53, accountNumber, sensKey, date);
//        body.put("PAN", temp2);
//        optionalFields.append("2|");
        //3 11 14 23 25 35 36 41 42 47 49 52 53 55 60 64
        body.put("PRO_COD", "310000");
        optionalFields.append("3|");
        body.put("CSEQ_NO", serialNumber);
        System.out.println("pos终端流水号：" + serialNumber);
        optionalFields.append("11|");
        if (!"".equals(bit14.trim())) {
            body.put("EXP_DT", bit14);
            optionalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {
            body.put("IN_MOD", "021");
            optionalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optionalFields.append("22|");
        }
        if (!"".equals(bit23.trim())) {
            body.put("SEP_NUM", bit23);
            optionalFields.append("23|");
        }
        body.put("CON_MOD", "00");
        optionalFields.append("25|");
        body.put("PIN_CAP_CODE", "12");
        optionalFields.append("26|");
        if (!"".equals(trk2.trim())) {
            //对后16位加密
            trk2 = DesUtil.encryptHanXinTrack(trk2, trkKey, mainKey);
            //替换掉原trk 数据的后16位
            body.put("TRACK_2", trk2);
            optionalFields.append("35|");
        }
        if (!"".equals(trk3.trim())) {
            trk3 = DesUtil.encryptHanXinTrack(trk3, trkKey, mainKey);
            body.put("TRACK_3", trk3);
            optionalFields.append("36|");
        }
        body.put("TRM_NO", this.posNo);
        optionalFields.append("41|");
        body.put("MERC_CD", this.shopCode);
        optionalFields.append("42|");
        //47域为机构号 + ip
        String temp47 = "SD=" + orgId +"|IP=" + localIp;
        System.out.println("47域的内容为: " + temp47);
        body.put("F47", temp47);
        optionalFields.append("47|");
        body.put("CCY", "156");
        optionalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optionalFields.append("52|");
        body.put("SECUR_INF", temp53);
        optionalFields.append("53|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optionalFields.append("55|");
        }
        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "01" + this.batch + "000");
            optionalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "01" + this.batch + "00050");
            optionalFields.append("60|");
        }
        body.put("F64", "");
        optionalFields.append("64");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "HANXIN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22,request.length()-16);
        String macstr = TestDes.MakeECBMac(macKey, sub, mainKey);//加密操作,传参问题
        body.put("F64", macstr);
        System.out.println("optionalFields " + optionalFields.toString());
        //生成报文
        System.out.println("翰鑫查询余额生成请求报文...");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "HANXIN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        for (int i=0; i<unMacMessage.length; i++) {
            System.out.print(unMacMessage[i] + ",");
        }
        System.out.println();
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        wf.log("翰鑫查询余额请求报文为：" + req, "调试");
        System.out.println("翰鑫查询余额请求报文为：" + req);
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, Integer.valueOf(port));
        String res = ByteUtils.byte2HexStr(response, false);
        System.out.println("翰鑫查询余额响应报文是：" + res);
        if ((!"-1".equals(res)) && (!"".equals(res))) {
            wf.log("翰鑫查询余额响应报文为：" + res, "调试");
            try {
                PosUtil.parse8583("HANXIN", res);
                //解析报文
                Map<String, String> map = Iso8583Parser.parse("HANXIN", response, true);
                //获取39、54域
                String result39 = map.get("39");
                if ("00".equals(result39)){
                    String result54 = map.get("54");
                    String AmountStr = PosUtil.handleBalance(result54);
                    QueryMsg = "0" + "_" + result39 + "_" + AmountStr;
                }else {
                    QueryMsg = "0" + "_" + result39;
                }
                //获取域值信息，处理返回数据
            }catch (Exception e) {
                e.printStackTrace();
                System.out.println("翰鑫查询余额解析错误");
                wf.log("翰鑫查询余额解析错误", "调试");
            }
        }else {
            QueryMsg = "-1_";
        }
        wf.log("翰鑫佘额查询返回数据:" + QueryMsg, "调试");
        return QueryMsg;
    }
    /**
     * 消费
     *
     * @param trk2          二磁道数据
     * @param trk3          三磁道数据
     * @param pin           密码
     * @param money         交易金额
     * @param accountNumber 卡号
     * @param serialNumber  订单号
     * @param bit23         IC卡序列号
     * @param bit55         IC卡 55 域
     * @param bit14         IC卡 序列号
     * @return 返回消费相关信息
     * @throws Exception
     */
    public String BillPayment(String trk2, String trk3, String pin, String money, String accountNumber, String serialNumber, String bit23, String bit55, String bit14) throws Exception {
        Date date = new Date();
        String temp53 = TimeUtils.getDateTime(date, "ddHHmmss") + NumberUtil.generateRandom8Number(8);
        //String des_pin = TestDes.PosEncryptPin(temp53, pin, pinKey, mainKey, date);//不需要主账号
        String des_pin = TestDes.MakeDesPin(accountNumber, pin, pinKey, mainKey);
        String comsumeMsg = "";
        String TYPE_ID = "0200";
        String mustFields = "";
        StringBuffer optionalFields = new StringBuffer("");
        HashMap<String,String> body = new HashMap<String,String>();
        wf.log("-------------------请求包域值信息-------------------", "调试");
        body.put("TPDU", this.tpdu);
        body.put("HEAD", this.header);
        //第2 61 62域要加密
//        String temp2 = TestDes.encryptSpecial(temp53, accountNumber, sensKey, date);
//        body.put("PAN", temp2);
//        optionalFields.append("2|");
        body.put("PRO_COD", "000000");
        optionalFields.append("3|");
        body.put("TTXN_AMT", money);
        optionalFields.append("4|");
        body.put("CSEQ_NO", serialNumber);
        optionalFields.append("11|");
        if (!"".equals(bit14.trim())) {
            body.put("EXP_DT", bit14);
            optionalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {
            body.put("IN_MOD", "021");
            optionalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optionalFields.append("22|");
        }
        if (!"".equals(bit23.trim())) {
            body.put("SEP_NUM", bit23);
            optionalFields.append("23|");
        }
        body.put("CON_MOD", "00");
        optionalFields.append("25|");
        body.put("PIN_CAP_CODE", "12");
        optionalFields.append("26|");
        if (!"".equals(trk2.trim())) {
            trk2 = DesUtil.encryptHanXinTrack(trk2, trkKey, mainKey);
            body.put("TRACK_2", trk2);
            optionalFields.append("35|");
        }
        if (!"".equals(trk3.trim())) {
            trk3 = DesUtil.encryptHanXinTrack(trk3, trkKey, mainKey);
            body.put("TRACK_3", trk3);
            optionalFields.append("36|");
        }
        body.put("TRM_NO", this.posNo);
        optionalFields.append("41|");
        body.put("MERC_CD", this.shopCode);
        optionalFields.append("42|");
        String temp47 = "SD=" + orgId +"|IP=" + localIp;
        System.out.println("47域的内容为: " + temp47);
        body.put("F47", temp47);
        optionalFields.append("47|");
        body.put("CCY", "156");
        optionalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optionalFields.append("52|");
        body.put("SECUR_INF", temp53);
        optionalFields.append("53|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optionalFields.append("55|");
        }
        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "22" + this.batch + "000");
            optionalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "22" + this.batch + "00050");
            optionalFields.append("60|");
        }
//        body.put("RESE_PRI_63", this.operator);
//        optionalFields.append("63|");
        body.put("F64", "");
        optionalFields.append("64");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "HANXIN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22,request.length()-16);
        //63域是否要出现
        String macstr = TestDes.MakeECBMac(macKey, sub, mainKey);//加密操作,传参问题
        body.put("F64", macstr);
        System.out.println("optionalFields " + optionalFields.toString());
        //生成报文
        System.out.println("翰鑫消费生成请求报文...");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "HANXIN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        for (int i=0; i<unMacMessage.length; i++) {
            System.out.print(unMacMessage[i] + ",");
        }
        System.out.println();
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        wf.log("翰鑫消费请求报文为：" + req, "调试");
        System.out.println("翰鑫消费请求报文为：" + req);
        //发送请求报文，并且返回响应
        System.out.println("ipAdd" + ipAddr + "--------------------" + "IPort" + port);
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, Integer.valueOf(port));
        String res = ByteUtils.byte2HexStr(response, false);
        System.out.println("翰鑫消费响应报文是：" + res);
        wf.log("翰鑫消费响应报文为：" + res, "调试");
        try {
            PosUtil.parse8583("HANXIN", res);
            //解析报文,返回解析的域map
            Map<String, String> map = Iso8583Parser.parse("HANXIN", response, true);
            //需要获取2,4,11,12,13,14,37,38,39域信息
            String result2 = map.get("2");
            String result4 = map.get("4");
            String result11 = map.get("11");
            String result12 = map.get("12");
            String result13 = map.get("13");
            String result14 = map.get("14");
            String result37 = map.get("37");
            String result38 = map.get("38");
            String result39 = map.get("39");
            comsumeMsg = "0_" + result2 + "_" +result4 + "_" +result11 + "_" + result12 + "_" +result13 + "_" + result14 + "_" +result37 + "_" +result38 +"_"+result39;
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("翰鑫消费响应报文解析错误");
            wf.log("翰鑫消费响应报文解析错误", "调试");
        }
        wf.log("翰鑫消费返回数据:" + comsumeMsg, "调试");
        return comsumeMsg;
    }
    /**
     * 消费冲正（交易）
     *
     * @param trk2 二磁道数据
     * @param trk3 三磁道数据
     * @return 订单信息
     * @throws Exception
     */
    public String unBillPayment(String pin, String trk2, String trk3, String money, String accountNumber, String serialNumber, String bit38, String bit23, String bit55, String bit14, String bit39) throws Exception {
        Date date = new Date();
        String temp53 = TimeUtils.getDateTime(date, "ddHHmmss") + NumberUtil.generateRandom8Number(8);
        String des_pin = TestDes.MakeDesPin(accountNumber, pin, pinKey, mainKey);//不需要主账号
        String QueryMsg = "";
        String typeCode = "0400";//消息类型
        String mustFields = "";
        StringBuffer optinalFields = new StringBuffer("");
        HashMap<String, String> body = new HashMap<String, String>();
        body.put("TPDU", this.tpdu);
        body.put("HEAD",this.header);
        //2 3 4 11 14 22 23 25 38 39 41 42 47 49 52 53 55 60 64
        body.put("PAN", accountNumber);
        optinalFields.append("2|");
        body.put("PRO_COD", "200000");//交易处理码 3
        optinalFields.append("3|");
        body.put("TTXN_AMT", money);//交易金额 4
        optinalFields.append("4|");
        body.put("CSEQ_NO", serialNumber);//交易流水号 同原交易
        optinalFields.append("11|");
        if (StringUtils.isNotBlank(bit55)){
            body.put("EXP_DT",bit14);
            optinalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {//服务点输入方式码 22
            body.put("IN_MOD", "021");
            optinalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optinalFields.append("22|");
        }
        if (!"".equals(bit23.trim())) {
            body.put("SEP_NUM", bit23);
            optinalFields.append("23|");
        }
        body.put("CON_MOD", "00");//服务点条件码 25
        optinalFields.append("25|");
//        body.put("PIN_CAP_CODE", "06");
//        optinalFields.append("26|");//服务点PIN获取码 26
//        if (!"".equals(trk2.trim())) {
//            trk2 = DesUtil.encryptHanXinTrack(trk2, trkKey, mainKey);
//            body.put("TRACK_2", trk2);
//            optinalFields.append("35|");
//        }
//        if (!"".equals(trk3.trim())) {
//            trk3 = DesUtil.encryptHanXinTrack(trk3, trkKey, mainKey);
//            body.put("TRACK_3", trk3);
//            optinalFields.append("36|");
//        }
        //38域需要判断应答码中是否存在
        if (StringUtils.isNotBlank(bit38)){
            body.put("AUT_CD", bit38);
            optinalFields.append("38|");
        }
        //授权标识应答码 38 如果原始交易的应答中有授权码，则须填入原交易授权码 从响应报文中获取
        //TODO 39域可能是补位之后的结果,需要做处理 截取后两位
        if (StringUtils.isNotBlank(bit39) && bit39.length() == 4){
            bit39 = bit39.substring(2);
        }else{
            bit39 = "98";
        }
        body.put("CPSCOD",bit39);//应答码 39 请求时为冲正原因，见注  交易报文中获取
        optinalFields.append("39|");
        body.put("TRM_NO", this.posNo);//受卡机终端标识码 41 同原消费交易
        optinalFields.append("41|");
        body.put("MERC_CD", this.shopCode);//受卡方标识码 42
        optinalFields.append("42|");
        String temp47 = "SD=" + orgId +"|IP=" + localIp;
        System.out.println("47域的内容为: " + temp47);
        body.put("F47", temp47);
        optinalFields.append("47|");
        body.put("CCY", "156");//交易货币代码 49
        optinalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optinalFields.append("52|");
        body.put("SECUR_INF", temp53);
        optinalFields.append("53|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optinalFields.append("55|");
        }
        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "23" + this.batch + "000");
            optinalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "23" + this.batch + "00050");
            optinalFields.append("60|");
        }
        body.put("F64", "");
        optinalFields.append("64");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22,request.length()-16);
        String macstr = TestDes.MakeECBMac(macKey, sub, mainKey);//加密操作,传参问题
        body.put("F64", macstr);
        System.out.println("optionalFields " + optinalFields.toString());
        //生成报文
        System.out.println("翰鑫消费冲正生成请求报文...");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        for (int i=0; i<unMacMessage.length; i++) {
            System.out.print(unMacMessage[i] + ",");
        }
        System.out.println();
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        wf.log("翰鑫消费冲正请求报文为：" + req, "调试");
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, Integer.valueOf(port));
        String res = ByteUtils.byte2HexStr(response, false);
        System.out.println("翰鑫消费冲正响应报文是：" + res);
        wf.log("翰鑫消费冲正响应报文为：" + res, "调试");
        try {
            PosUtil.parse8583("HANXIN", res);
            //解析报文
            byte[] bytes = ByteUtils.hexStringToByte(res);
            Map<String, String> map = Iso8583Parser.parse("HANXIN", bytes, true);
            //处理2,4,11,12,13,14,37,38,39,44,61域信息
            String temp2 = map.get("2");
            String temp4 = map.get("4");
            String temp11 = map.get("11");
            String temp12 = map.get("12");
            String temp13 = map.get("13");
            String temp14 = map.get("14");
            String temp37 = map.get("37");
            String temp38 = map.get("38");
            String temp39 = map.get("39");
            String temp44 = map.get("44");
            String temp61 = map.get("61");
            QueryMsg = temp2+"_"+temp4+"_"+temp11+"_"+temp12+"_"+temp13+"_"+temp14+"_"+temp37+"_"+temp38+"_"+temp39+"_"+temp44+"_"+temp61;
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("翰鑫消费冲正响应报文解析错误");
            wf.log("翰鑫消费冲正响应报文解析错误", "调试");
        }
        wf.log("翰鑫消费冲正返回数据:" + QueryMsg, "调试");
        return QueryMsg;
    }


    public static void main(String[] argus) throws Exception {
        //chexiao();
        //PosUtil.parse8583("HANXIN","60000600006010030000000200302004802CC2981920000000000000010010003002100040374033920025480072D2005538C19B0CC7DC33003030303030303436393031313431303545313130303030313533323731313031303730313130303031003553443D3137333636353638333932333237317C49503D312E3230322E3234382E31333331353649E72765554A66C10310510531923847001123000001000000123030303030313130303032393830433235303937");
        chongzheng();
    }
    /**
     * 冲正
     * @return
     */
    public static void chongzheng() throws Exception{
        String ip = "58.246.136.11";           //ip
        Integer port = 18580;                  //端口
        String tpdu = "6000060000";            //tpdu
        String header = "601003000000";        //header
        String typeCode = "0400";              //消息类型

        String pan = "4033920025480072";       //2域
        String money = "000000000100";         //4域
        String serial = "100030";                    //11域 同原交易

        String bit14 = "";                     //14域
        String bit23 = "";                     //23域
        String trk2 = "374033920025480072D2005538C19B0CC7DC3300";                      //35域
        String trk3 = "";                      //36域
        String bit37 = "000000469016";         //37域  原消费的交易参考号
        String bit38 = "A29DD2";               //38域
        String bit39 = "00";                   //39域
        String posNo = "10000153";             //41域
        String shopCode = "271101070110001";   //42域
        String orgId = "173665683923271";
        String myIp = "1.202.248.133";
        String temp47 = "SD=" + orgId +"|IP=" + myIp; //47域

        //53域
        Date date = new Date();
        String temp53 = TimeUtils.getDateTime(date, "ddHHmmss") + NumberUtil.generateRandom8Number(8);
        String bit55 = "";                     //55域
        String batch = "000001";
        //TODO 61域,原消费的交易的批次号 和  原消费交易的流水号
        String serialNumber = "100030";
        String bit61 = batch + serialNumber;   //61域,原交易流水号

        String MasterKey = DesUtil.decode3DES("7E7D2736053F3B522942052D27BDFBD3","0EDE6F2886FE8D838667748AC055CCF3");       //主密钥   data, key
        String pinKey = "5F7BD926CA6F64D6FEE58B2ACBA461CC";                                 //pin秘钥
        String MacKey = "CE711216CD97D94AC10EBF95BDAF37AE"; //mac秘钥
        String trkKey = "8E32B5159580C9871FC90C559DCAB8BC";                                 //trk秘钥
        //52域
        String pin = "888888";
        String des_pin = TestDes.MakeDesPin(pan , pin, pinKey, MasterKey);


        String mustFields = "";
        StringBuffer optinalFields = new StringBuffer("");
        HashMap<String, String> body = new HashMap<String, String>();
        body.put("TPDU", tpdu);
        body.put("HEAD", header);
        //3 4 11 22 25 38 39 41 42 44 49 60 61 64
        body.put("PAN", pan);
        optinalFields.append("2|");
        body.put("PRO_COD", "200000");//交易处理码 3 跟原交易相同
        optinalFields.append("3|");
        body.put("TTXN_AMT", money);//交易金额 4  跟原交易相同
        optinalFields.append("4|");
        body.put("CSEQ_NO", serial); //受卡方系统跟踪号
        optinalFields.append("11|");
        if (!"".equals(bit14)){
            body.put("EXP_DT", bit14);//14
            optinalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {//服务点输入方式码 22 跟原交易相同
            body.put("IN_MOD", "021");
            optinalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optinalFields.append("22|");
        }
        if (!"".equals(bit23)){
            body.put("SEP_NUM", bit23);
            optinalFields.append("23|");
        }
        body.put("CON_MOD", "00");//服务点条件码 25
        optinalFields.append("25|");
//        if (!"".equals(trk2.trim())) {
//            trk2 = DesUtil.encryptHanXinTrack(trk2, trkKey, MasterKey);
//            body.put("TRACK_2", trk2);
//            optinalFields.append("35|");
//        }
//        if (!"".equals(trk3.trim())) {
//            trk3 = DesUtil.encryptHanXinTrack(trk3, trkKey, MasterKey);
//            body.put("TRACK_3", trk3);
//            optinalFields.append("36|");
//        }
//        if (StringUtils.isNotBlank(bit37)){//原消费的交易参考号
//            body.put("RET_RE_NO", bit37);
//            optinalFields.append("37|");
//        }
        if (StringUtils.isNotBlank(bit38)){
            body.put("AUT_CD", bit38);//授权标识应答码 38 如果原始交易的应答中有授权码，则须填入原交易授权码 从响应报文中获取
            optinalFields.append("38|");
        }
        body.put("CPSCOD", bit39);
        optinalFields.append("39|");
        body.put("TRM_NO", posNo);//受卡机终端标识码 41 同原消费交易
        optinalFields.append("41|");
        body.put("MERC_CD", shopCode);//受卡方标识码 42
        optinalFields.append("42|");
        body.put("F47", temp47);//47域
        optinalFields.append("47|");
        body.put("CCY", "156");//交易货币代码 49
        optinalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optinalFields.append("52|");
        body.put("SECUR_INF", temp53);
        optinalFields.append("53|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optinalFields.append("55|");
        }
        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "23" + batch + "000");
            optinalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "23" + batch + "00050");
            optinalFields.append("60|");
        }
        optinalFields.append("64");
        body.put("F64", "");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22, request.length() - 16);
        String macstr = TestDes.MakeECBMac(MacKey, sub, MasterKey);//加密操作,传参问题
        body.put("F64", macstr);
        System.out.println("optionalFields " + optinalFields.toString());
        //生成报文
        System.out.println("翰鑫消费冲正生成请求报文...");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        for (int i=0; i<unMacMessage.length; i++) {
            System.out.print(unMacMessage[i] + ",");
        }
        System.out.println();
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        System.out.println("消费的冲正报文为: " + req);
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ip, port);
        String res = ByteUtils.byte2HexStr(response, false);
        System.out.println("翰鑫消费冲正响应报文是：" + res);
        try {
            //解析报文
            PosUtil.parse8583("HANXIN", res);
        }catch (Exception e) {
            e.printStackTrace();

        }
    }
    /**
     * 撤销
     */
    public static void chexiao(){
        String ip = "58.246.136.11";           //ip
        Integer port = 18580;                  //端口
        String tpdu = "6000060000";            //tpdu
        String header = "601003000000";        //header
        String typeCode = "0200";              //消息类型

        String pan = "4033920025480072";    //2域
        String money = "000000000100";         //4域
        String serial = "100031";                    //11域

        String bit14 = "";                     //14域
        String bit23 = "";                     //23域
        String trk2 = "374033920025480072D2005538C19B0CC7DC3300";                      //35域
        String trk3 = "";                      //36域
        String bit37 = "000000469011";                     //37域  原消费的交易参考号
        String bit38 = "4105E1";    //38域
        String posNo = "10000153";             //41域
        String shopCode = "271101070110001";   //42域
        String orgId = "173665683923271";
        String myIp = "1.202.248.133";
        String temp47 = "SD=" + orgId +"|IP=" + myIp; //47域

        //53域
        Date date = new Date();
        String temp53 = TimeUtils.getDateTime(date, "ddHHmmss") + NumberUtil.generateRandom8Number(8);
        String bit55 = "";                     //55域
        String batch = "000001";
        //TODO 61域,原消费的交易的批次号 和  原消费交易的流水号
        String serialNumber = "100029";
        String bit61 ="12" + batch + serialNumber;   //61域,原交易流水号

        String MasterKey = DesUtil.decode3DES("7E7D2736053F3B522942052D27BDFBD3","0EDE6F2886FE8D838667748AC055CCF3");       //主密钥   data, key
        String pinKey = "5F7BD926CA6F64D6FEE58B2ACBA461CC";                                 //pin秘钥
        String MacKey = "CE711216CD97D94AC10EBF95BDAF37AE"; //mac秘钥
        String trkKey = "8E32B5159580C9871FC90C559DCAB8BC";                                 //trk秘钥
        //52域
        String pin = "888888";
        String des_pin = TestDes.MakeDesPin(pan , pin, pinKey, MasterKey);


        String mustFields = "";
        StringBuffer optinalFields = new StringBuffer("");
        HashMap<String, String> body = new HashMap<String, String>();
        body.put("TPDU", tpdu);
        body.put("HEAD", header);
        //3 4 11 22 25 38 39 41 42 44 49 60 61 64
        body.put("PRO_COD", "200000");//交易处理码 3 跟原交易相同
        optinalFields.append("3|");
        body.put("TTXN_AMT", money);//交易金额 4  跟原交易相同
        optinalFields.append("4|");
        body.put("CSEQ_NO", serial); //受卡方系统跟踪号
        optinalFields.append("11|");
        if (!"".equals(bit14)){
            body.put("EXP_DT", bit14);//14
            optinalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {//服务点输入方式码 22 跟原交易相同
            body.put("IN_MOD", "021");
            optinalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optinalFields.append("22|");
        }
        if (!"".equals(bit23)){
            body.put("SEP_NUM", bit23);
            optinalFields.append("23|");
        }
        body.put("CON_MOD", "00");//服务点条件码 25
        optinalFields.append("25|");
        if (!"".equals(trk2.trim())) {
            //trk2 = DesUtil.encryptHanXinTrack(trk2, trkKey, MasterKey);
            body.put("TRACK_2", trk2);
            optinalFields.append("35|");
        }
        if (!"".equals(trk3.trim())) {
            //trk3 = DesUtil.encryptHanXinTrack(trk3, trkKey, MasterKey);
            body.put("TRACK_3", trk3);
            optinalFields.append("36|");
        }
        if (StringUtils.isNotBlank(bit37)){//原消费的交易参考号
            body.put("RET_RE_NO", bit37);
            optinalFields.append("37|");
        }
        if (StringUtils.isNotBlank(bit38)){
            body.put("AUT_CD", bit38);//授权标识应答码 38 如果原始交易的应答中有授权码，则须填入原交易授权码 从响应报文中获取
            optinalFields.append("38|");
        }
        body.put("TRM_NO", posNo);//受卡机终端标识码 41 同原消费交易
        optinalFields.append("41|");
        body.put("MERC_CD", shopCode);//受卡方标识码 42
        optinalFields.append("42|");
        body.put("F47", temp47);//47域
        optinalFields.append("47|");
        body.put("CCY", "156");//交易货币代码 49
        optinalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optinalFields.append("52|");
        body.put("SECUR_INF", temp53);
        optinalFields.append("53|");

        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "23" + batch + "000");
            optinalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "23" + batch + "00050");
            optinalFields.append("60|");
        }
        //TODO 61域,原消费的交易的批次号 和  原消费交易的流水号
        body.put("ORI_MES", bit61);
        optinalFields.append("61|");
        optinalFields.append("64");
        body.put("F64", "");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22, request.length() - 16);
        String macstr = TestDes.MakeECBMac(MacKey, sub, MasterKey);//加密操作,传参问题
        body.put("F64", macstr);
        System.out.println("optionalFields " + optinalFields.toString());
        //生成报文
        System.out.println("翰鑫消费撤销生成请求报文...");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optinalFields.toString(), typeCode, body, "HANXIN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        for (int i=0; i<unMacMessage.length; i++) {
            System.out.print(unMacMessage[i] + ",");
        }
        System.out.println();
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        System.out.println("消费的撤销报文为: " + req);
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ip, port);
        String res = ByteUtils.byte2HexStr(response, false);
        System.out.println("翰鑫消费撤销响应报文是：" + res);
        try {
            //解析报文
            PosUtil.parse8583("HANXIN", res);
        }catch (Exception e) {
            e.printStackTrace();

        }
    }

}
